from decimal import Decimal
from flask import Flask, current_app, session, request, url_for,send_from_directory, redirect
from .config import Config
import os
from dotenv import load_dotenv

from .extensions import db, login_manager, babel, csrf
from .filters import to_public
from flask_wtf.csrf import generate_csrf

load_dotenv()

CURRENCY_SYMBOLS = {
    'CNY': '¥', 'USD': '$', 'EUR': '€', 'HKD': 'HK$', 'JPY': '¥'
}

UNIT_LABELS = {
    'length': {'mm': 'mm', 'cm': 'cm', 'in': 'in'},
    'weight': {'g': 'g', 'kg': 'kg', 'oz': 'oz'},
}


def fmt_size(val, unit):
    if val is None or not unit: return ''
    return f"{val:g} {UNIT_LABELS['length'].get(unit, unit)}"


def fmt_weight(val, unit):
    if val is None or not unit: return ''
    return f"{val:g} {UNIT_LABELS['weight'].get(unit, unit)}"


def product_material(p, lang:str|None):
    # 优先取 i18n.material
    if lang and lang != 'zh':
        for t in p.i18n:
            if t.lang and t.lang.lower().startswith(lang.lower()):
                return t.material or p.material
    return p.material


def format_price_minor(value_minor, currency='CNY'):
    if value_minor is None:
        return ''
    try:
        amt = Decimal(value_minor) / Decimal(100)
        sym = CURRENCY_SYMBOLS.get((currency or 'CNY').upper(), '')
        return f"{sym}{amt:,.2f} {currency.upper()}"
    except Exception:
        return ''


def _to_static(path: str) -> str:
    if not path:
        return ''
    # 已经是 /static/ 开头
    if path.startswith('/static/'):
        return path
    # 形如 static/uploads/xxx
    if path.startswith('static/'):
        return '/' + path
    # 形如 uploads/xxx 或 /uploads/xxx —— 统一改成 /static/uploads/xxx
    if path.startswith('/uploads/'):
        return '/static' + path
    if path.startswith('uploads/'):
        return '/static/' + path
    # 其它情况，按相对 static 的文件处理
    return url_for('static', filename=path.lstrip('/'))


def int_if_whole(value):
    try:
        f = float(value)
        if f.is_integer():
            return str(int(f))
        return str(f)
    except:
        return value


def get_locale():
    # session > ?lang=xx > 默认
    lang = (session.get('lang') or request.args.get('lang') or '').lower()
    allowed = current_app.config.get('LANGUAGES', ['zh', 'en'])
    if lang in allowed:
        return lang
    return current_app.config.get('BABEL_DEFAULT_LOCALE', 'en')


@login_manager.unauthorized_handler
def _unauth_redirect():
    next_url = request.url
    # 后台蓝图统一以 /admin 开头
    if request.path.startswith('/admin'):
        return redirect(url_for('admin.login', next=next_url))
    # 其余走前台会员登录（你的前台蓝图叫 auth 或 front，请按实际改）
    return redirect(url_for('auth.login', next=next_url))
    # 如果你的前台路由是 front.login，则改成：
    # return redirect(url_for('front.login', next=next_url))


def create_app():

    app = Flask(__name__, instance_relative_config=True)
    app.config.from_object(Config)

    os.makedirs(app.instance_path, exist_ok=True)
    os.makedirs(os.path.join(app.root_path, 'static', 'uploads'), exist_ok=True)


    db.init_app(app)
    login_manager.init_app(app)
    babel.init_app(app, locale_selector=get_locale)

    login_manager.login_view = 'front.login'  # 未登录跳转
    login_manager.login_message_category = 'info'

    # --- 现在再设置 user_loader，避免循环 ---
    from .models import AdminUser, CustomerUser

    @login_manager.user_loader
    def load_user(mixed_id: str):
        try:
            kind, raw_id = mixed_id.split(':', 1)
        except ValueError:
            # 老会话兼容：无前缀默认 admin
            kind, raw_id = 'admin', mixed_id
        if kind == 'cust':
            return CustomerUser.query.get(int(raw_id))
        if kind == 'admin':
            return AdminUser.query.get(int(raw_id))
        return None

    # 注册蓝图
    from app.routes.routes_front import bp as front_bp
    from app.routes.routes_admin import bp as admin_bp
    from app.routes.routes_order import shop_bp
    from app.routes.routes_paypal import paypal_bp
    from app.routes.routes_admin_order import admin_orders_bp

    app.register_blueprint(front_bp)
    app.register_blueprint(admin_bp, url_prefix='/admin')
    app.register_blueprint(shop_bp)
    app.register_blueprint(paypal_bp)
    app.register_blueprint(admin_orders_bp)
    csrf.init_app(app)
    os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)

    app.jinja_env.filters['to_static'] = _to_static
    app.jinja_env.filters['fmt_price'] = format_price_minor
    app.jinja_env.filters['fmt_size'] = fmt_size
    app.jinja_env.filters['fmt_weight'] = fmt_weight
    app.jinja_env.filters['p_material'] = lambda p, lang: product_material(p, lang)
    app.jinja_env.filters['to_public'] = to_public
    # with app.app_context():
    #     db.create_all()

    @app.route('/uploads/<path:filename>')
    def uploaded_file(filename):
        return send_from_directory(app.config['UPLOAD_FOLDER'], filename)

    @app.context_processor
    def inject_conf():
        return {'CONF': app.config}

    @app.context_processor
    def inject_csrf():
        # 这样模板里就能直接用 {{ csrf_token() }}
        return dict(csrf_token=generate_csrf)

    @app.template_filter('int_if_whole')
    def int_if_whole_filter(value):
        return int_if_whole(value)

    return app